package com.hhf.springboot.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hhf.springboot.common.ChartDataItem;
import com.hhf.springboot.common.DataGroupByDateDTO;
import com.hhf.springboot.common.ErrorCode;
import com.hhf.springboot.constant.CommonConstant;
import com.hhf.springboot.exception.BusinessException;
import com.hhf.springboot.exception.ThrowUtils;
import com.hhf.springboot.mapper.OrderInfoMapper;
import com.hhf.springboot.model.dto.orderInfo.OrderInfoQueryRequest;
import com.hhf.springboot.model.dto.orderInfo.SalesStatisticsDTO;
import com.hhf.springboot.model.entity.BisheProject;
import com.hhf.springboot.model.entity.OrderInfo;
import com.hhf.springboot.model.entity.ServiceProject;
import com.hhf.springboot.model.entity.User;
import com.hhf.springboot.model.enums.OrderInfoStatusEnum;
import com.hhf.springboot.model.enums.OrderInfoTypeEnum;
import com.hhf.springboot.model.vo.OrderInfoVO;
import com.hhf.springboot.model.vo.UserVO;
import com.hhf.springboot.service.BisheProjectService;
import com.hhf.springboot.service.OrderInfoService;
import com.hhf.springboot.service.ServiceProjectService;
import com.hhf.springboot.service.UserService;
import com.hhf.springboot.utils.DateUtils;
import com.hhf.springboot.utils.SqlUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单信息服务实现
 *
 * @author hhf
 * @from <a href="https://gitee.com/hanhuaifei/projects">我的gitee</a>
 * @Date 2024/9/26
 */
@Service
@Slf4j
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Resource
    private UserService userService;

    @Resource
    private BisheProjectService bisheProjectService;

    @Resource
    private ServiceProjectService serviceProjectService;

    /**
     * 校验数据
     *
     * @param orderInfo
     * @param add       对创建的数据进行校验
     */
    @Override
    public void validOrderInfo(OrderInfo orderInfo, boolean add) {
        ThrowUtils.throwIf(orderInfo == null, ErrorCode.PARAMS_ERROR);
        // 从对象中取值
        String name = orderInfo.getName();
        Long targetId = orderInfo.getTargetId();
        String type = orderInfo.getType();

        // 创建数据时，参数不能为空
        if (add) {
            // 补充校验规则
            ThrowUtils.throwIf(StringUtils.isBlank(name), ErrorCode.PARAMS_ERROR);
        }
        // 修改数据时，有参数则校验
        // 补充校验规则
        if (StringUtils.isNotBlank(name)) {
            ThrowUtils.throwIf(name.length() > 80, ErrorCode.PARAMS_ERROR, "名称过长");
        }

        //查询订单的target是否存在
        OrderInfoTypeEnum orderInfoTypeEnum = OrderInfoTypeEnum.getEnumByValue(type);
        switch (orderInfoTypeEnum) {
            case PROJECT -> {
                BisheProject bisheProject = bisheProjectService.getById(targetId);
                if (bisheProject == null) {
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "目标不存在");
                }
            }
            case SERVICE -> {
                ServiceProject serviceProject = serviceProjectService.getById(targetId);
                if (serviceProject == null){
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "目标不存在");
                }
            }
        }
    }

    /**
     * 获取查询条件
     *
     * @param orderInfoQueryRequest
     * @return
     */
    @Override
    public QueryWrapper<OrderInfo> getQueryWrapper(OrderInfoQueryRequest orderInfoQueryRequest) {
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        if (orderInfoQueryRequest == null) {
            return queryWrapper;
        }
        // 从对象中取值
        Long id = orderInfoQueryRequest.getId();
        String name = orderInfoQueryRequest.getName();
        Integer needCode = orderInfoQueryRequest.getNeedCode();
        Integer needDoc = orderInfoQueryRequest.getNeedDoc();
        Integer needDeploy = orderInfoQueryRequest.getNeedDeploy();
        Integer amount = orderInfoQueryRequest.getAmount();
        String orderNo = orderInfoQueryRequest.getOrderNo();
        Integer status = orderInfoQueryRequest.getStatus();
        Long userId = orderInfoQueryRequest.getUserId();
        Date payTime = orderInfoQueryRequest.getPayTime();
        Date createTime = orderInfoQueryRequest.getCreateTime();
        String sortField = orderInfoQueryRequest.getSortField();
        String sortOrder = orderInfoQueryRequest.getSortOrder();
        // 补充需要的查询条件
        // 模糊查询
        queryWrapper.like(StringUtils.isNotBlank(name), "name", name);
        // 精确查询
        queryWrapper.eq(ObjectUtils.isNotEmpty(id), "id", id);
        queryWrapper.eq(ObjectUtils.isNotEmpty(userId), "user_id", userId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(orderNo), "order_no", orderNo);
        queryWrapper.eq(ObjectUtils.isNotEmpty(amount), "amount", amount);
        queryWrapper.eq(ObjectUtils.isNotEmpty(status), "status", status);
        queryWrapper.eq(ObjectUtils.isNotEmpty(needCode), "need_code", needCode);
        queryWrapper.eq(ObjectUtils.isNotEmpty(needDoc), "need_doc", needDoc);
        queryWrapper.eq(ObjectUtils.isNotEmpty(needDeploy), "need_deploy", needDeploy);
        // 时间查询
        if (createTime != null) {
            LocalDateTime localDateTime = createTime.toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime();
            Date startDate = Date.from(localDateTime.withHour(0).withMinute(0).withSecond(0).atZone(ZoneId.systemDefault()).toInstant());
            Date endDate = Date.from(localDateTime.withHour(23).withMinute(59).withSecond(59).atZone(ZoneId.systemDefault()).toInstant());
            queryWrapper.between("create_time", startDate, endDate);
        }
        if (payTime != null) {
            LocalDateTime localDateTime = payTime.toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime();
            Date startDate = Date.from(localDateTime.withHour(0).withMinute(0).withSecond(0).atZone(ZoneId.systemDefault()).toInstant());
            Date endDate = Date.from(localDateTime.withHour(23).withMinute(59).withSecond(59).atZone(ZoneId.systemDefault()).toInstant());
            queryWrapper.between("pay_time", startDate, endDate);
        }

        // 排序规则
        queryWrapper.orderBy(SqlUtils.validSortField(sortField),
                sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);
        return queryWrapper;
    }

    /**
     * 获取订单信息封装
     *
     * @param orderInfo
     * @param request
     * @return
     */
    @Override
    public OrderInfoVO getOrderInfoVO(OrderInfo orderInfo, HttpServletRequest request) {
        // 对象转封装类
        OrderInfoVO orderInfoVO = OrderInfoVO.objToVo(orderInfo);

        // 可以根据需要为封装对象补充值，不需要的内容可以删除
        // region 可选
        // 1. 关联查询用户信息
        Long userId = orderInfo.getUserId();
        User user = null;
        if (userId != null && userId > 0) {
            user = userService.getById(userId);
        }
        UserVO userVO = userService.getUserVO(user);
        orderInfoVO.setUser(userVO);
        // endregion

        return orderInfoVO;
    }

    /**
     * 分页获取订单信息封装
     *
     * @param orderInfoPage
     * @param request
     * @return
     */
    @Override
    public Page<OrderInfoVO> getOrderInfoVOPage(Page<OrderInfo> orderInfoPage, HttpServletRequest request) {
        List<OrderInfo> orderInfoList = orderInfoPage.getRecords();
        Page<OrderInfoVO> orderInfoVOPage = new Page<>(orderInfoPage.getCurrent(), orderInfoPage.getSize(), orderInfoPage.getTotal());
        if (CollUtil.isEmpty(orderInfoList)) {
            return orderInfoVOPage;
        }
        // 对象列表 => 封装对象列表
        List<OrderInfoVO> orderInfoVOList = orderInfoList.stream().map(orderInfo -> {
            return OrderInfoVO.objToVo(orderInfo);
        }).collect(Collectors.toList());

        // 可以根据需要为封装对象补充值，不需要的内容可以删除
        // region 可选
        // 1. 关联查询用户信息
        Set<Long> userIdSet = orderInfoList.stream().map(OrderInfo::getUserId).collect(Collectors.toSet());
        Map<Long, List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream()
                .collect(Collectors.groupingBy(User::getId));
        // 填充信息
        orderInfoVOList.forEach(orderInfoVO -> {
            Long userId = orderInfoVO.getUserId();
            User user = null;
            if (userIdUserListMap.containsKey(userId)) {
                user = userIdUserListMap.get(userId).get(0);
            }
            orderInfoVO.setUser(userService.getUserVO(user));
        });
        // endregion

        orderInfoVOPage.setRecords(orderInfoVOList);
        return orderInfoVOPage;
    }

    /**
     * 分按日期分组查询订单信息新增数量
     *
     * @param beginDate 开始时间
     * @param endDate   结束时间
     * @return
     */
    @Override
    public List<DataGroupByDateDTO> countByDay(Date beginDate, Date endDate) {
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("DATE_FORMAT(create_time, '%Y-%m-%d') AS day", "COUNT(1) AS num");
        queryWrapper.ge("create_time", beginDate);
        queryWrapper.le("create_time", endDate);
        queryWrapper.groupBy("day");
        queryWrapper.orderByAsc("day");
        // 执行查询
        List<Map<String, Object>> results = this.baseMapper.selectMaps(queryWrapper);
        // 映射到 DataGroupByDateDTO
        return results.stream().map(result -> {
            DataGroupByDateDTO dto = new DataGroupByDateDTO();
            dto.setDay(DateUtils.parse(result.get("day").toString(), DateUtils.FMT_YMD));
            dto.setNum(((Number) result.get("num")).intValue()); // 修改为Integer类型
            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    public OrderInfo fillOrderInfo(OrderInfo orderInfo) {
        Long targetId = orderInfo.getTargetId();
        String type = orderInfo.getType();
        //计算价格
        Integer totalAmount = 0;
        OrderInfoTypeEnum orderInfoTypeEnum = OrderInfoTypeEnum.getEnumByValue(type);
        switch (orderInfoTypeEnum) {
            case PROJECT -> {
                BisheProject bisheProject = bisheProjectService.getById(targetId);
                if (orderInfo.getNeedCode() == 1) {
                    totalAmount += bisheProject.getCodePrice();
                }
                if (orderInfo.getNeedDoc() == 1) {
                    totalAmount += bisheProject.getDocPrice();
                }
                if (orderInfo.getNeedDeploy() == 1) {
                    totalAmount += 5000;
                }
            }
            case SERVICE -> {
                ServiceProject serviceProject = serviceProjectService.getById(targetId);
                if (orderInfo.getNeedDeploy() == 1) {
                    totalAmount += serviceProject.getPrice();
                }
            }
        }
        // 订单价格
        orderInfo.setAmount(totalAmount);
        // 生成订单号，可以使用时间戳+随机数的方式
        orderInfo.setOrderNo(generateOrderNo());
        // 交易ID通常在支付成功后由支付平台返回，初始可以为空
        orderInfo.setTransactionId(null);


        // 返回填充后的订单信息
        return orderInfo;
    }

    /**
     * 生成订单号
     * 格式：年月日时分秒+6位随机数
     *
     * @return 订单号
     */
    private String generateOrderNo() {
        // 使用时间戳作为订单号前缀
        String timestamp = DateUtils.format(new Date(), "yyyyMMddHHmmss");
        // 生成6位随机数
        long snowflakeId = IdUtil.getSnowflake(1, 1).nextId();
        // 将 ID 转换为字符串
        String snowflakeIdStr = String.valueOf(snowflakeId);
        String nextId = snowflakeIdStr.substring(snowflakeIdStr.length() - 6);
        return timestamp + nextId;
    }

    @Override
    public SalesStatisticsDTO getSalesStatistics() {
        SalesStatisticsDTO statisticsDTO = new SalesStatisticsDTO();

        // 只统计已支付的订单
        Integer paidStatus = OrderInfoStatusEnum.HAS_PAY.getValue();

        // 1. 计算总销售额
        QueryWrapper<OrderInfo> totalWrapper = new QueryWrapper<>();
        totalWrapper.select("IFNULL(SUM(amount), 0) as total_amount");
        totalWrapper.eq("status", paidStatus);
        Map<String, Object> totalResult = this.baseMapper.selectMaps(totalWrapper).get(0);
        Long totalSales = ((Number) totalResult.get("total_amount")).longValue();
        statisticsDTO.setTotalSales(totalSales);

        // 2. 计算今日销售额
        Date today = DateUtils.getNow();
        Date todayStart = DateUtils.getDayStartTime(today);
        Date todayEnd = DateUtils.getDayEndTime(today);

        QueryWrapper<OrderInfo> todayWrapper = new QueryWrapper<>();
        todayWrapper.select("IFNULL(SUM(amount), 0) as total_amount");
        todayWrapper.eq("status", paidStatus);
        todayWrapper.between("pay_time", todayStart, todayEnd);
        Map<String, Object> todayResult = this.baseMapper.selectMaps(todayWrapper).get(0);
        Long todaySales = ((Number) todayResult.get("total_amount")).longValue();
        statisticsDTO.setTodaySales(todaySales);

        // 计算昨日销售额
        Date yesterday = DateUtils.dayAfter(today, -1);
        Date yesterdayStart = DateUtils.getDayStartTime(yesterday);
        Date yesterdayEnd = DateUtils.getDayEndTime(yesterday);

        QueryWrapper<OrderInfo> yesterdayWrapper = new QueryWrapper<>();
        yesterdayWrapper.select("IFNULL(SUM(amount), 0) as total_amount");
        yesterdayWrapper.eq("status", paidStatus);
        yesterdayWrapper.between("pay_time", yesterdayStart, yesterdayEnd);
        Map<String, Object> yesterdayResult = this.baseMapper.selectMaps(yesterdayWrapper).get(0);
        Long yesterdaySales = ((Number) yesterdayResult.get("total_amount")).longValue();

        // 计算本周销售额
        Date thisWeekStart = DateUtils.getBeginDayOfWeek();
        Date thisWeekEnd = DateUtils.getEndDayOfWeek();

        QueryWrapper<OrderInfo> thisWeekWrapper = new QueryWrapper<>();
        thisWeekWrapper.select("IFNULL(SUM(amount), 0) as total_amount");
        thisWeekWrapper.eq("status", paidStatus);
        thisWeekWrapper.between("pay_time", thisWeekStart, thisWeekEnd);
        Map<String, Object> thisWeekResult = this.baseMapper.selectMaps(thisWeekWrapper).get(0);
        Long thisWeekSales = ((Number) thisWeekResult.get("total_amount")).longValue();

        // 计算上周销售额
        Date lastWeekStart = DateUtils.dayAfter(thisWeekStart, -7);
        Date lastWeekEnd = DateUtils.dayAfter(thisWeekEnd, -7);

        QueryWrapper<OrderInfo> lastWeekWrapper = new QueryWrapper<>();
        lastWeekWrapper.select("IFNULL(SUM(amount), 0) as total_amount");
        lastWeekWrapper.eq("status", paidStatus);
        lastWeekWrapper.between("pay_time", lastWeekStart, lastWeekEnd);
        Map<String, Object> lastWeekResult = this.baseMapper.selectMaps(lastWeekWrapper).get(0);
        Long lastWeekSales = ((Number) lastWeekResult.get("total_amount")).longValue();


        // 3.4. 计算日同比和周同比
        BigDecimal dayOnDayRate = calculateRate(todaySales, yesterdaySales);
        BigDecimal weekOnWeekRate = calculateRate(thisWeekSales, lastWeekSales);

        statisticsDTO.setDayOnDayRate(dayOnDayRate);
        statisticsDTO.setWeekOnWeekRate(weekOnWeekRate);


        // 计算总订单数
        long totalOrders = this.count();

        // 5. 计算已支付订单数
        QueryWrapper<OrderInfo> paidWrapper = new QueryWrapper<>();
        paidWrapper.eq("status", paidStatus);
        long paidOrders = this.count(paidWrapper);
        statisticsDTO.setPaidOrders(paidOrders);

        // 6. 计算支付转换率
        BigDecimal conversionRate = calculateConversionRate(paidOrders, totalOrders);
        statisticsDTO.setConversionRate(conversionRate);


        // 7. 获取最近15天的支付订单数据
        Date beginDate = DateUtils.dayAfter(today, -14); // 14天前（加上今天共15天）
        List<ChartDataItem> last15DaysPaymentData = getPaymentDataByDay(beginDate, today, paidStatus);
        statisticsDTO.setLast15DaysPaymentData(last15DaysPaymentData);


        // 8. 获取今日销售额
        List<ChartDataItem> todaySalesData = getSalesDataByHour(todayStart, todayEnd, paidStatus);
        statisticsDTO.setSalesDataToday(todaySalesData);

        // 9. 获取本周销售额
        List<ChartDataItem> weekSalesData = getSalesDataByDay(thisWeekStart, thisWeekEnd, paidStatus);
        statisticsDTO.setSalesDataWeek(weekSalesData);

        // 10. 获取本月销售额
        Date thisMonthStart = DateUtils.getBeginDayOfMonth();
        Date thisMonthEnd = DateUtils.getEndDayOfMonth();
        List<ChartDataItem> monthSalesData = getSalesDataByDay(thisMonthStart, thisMonthEnd, paidStatus);
        statisticsDTO.setSalesDataMonth(monthSalesData);

        // 11. 获取本年销售额
        Date thisYearStart = DateUtils.getBeginDayOfYear();
        Date thisYearEnd = DateUtils.getEndDayOfYear();
        List<ChartDataItem> yearSalesData = getSalesDataByMonth(thisYearStart, thisYearEnd, paidStatus);
        statisticsDTO.setSalesDataYear(yearSalesData);

        return statisticsDTO;
    }

    /**
     * 计算同比增长率
     *
     * @param current  当前值
     * @param previous 上一个值
     * @return 增长率，如果上一个值为0，则返回null
     */
    private BigDecimal calculateRate(Long current, Long previous) {
        if (previous == 0) {
            return null;
        }

        BigDecimal currentDecimal = new BigDecimal(current);
        BigDecimal previousDecimal = new BigDecimal(previous);

        // (当前值/上一个值) - 1
        return currentDecimal.divide(previousDecimal, 4, BigDecimal.ROUND_HALF_UP)
                .subtract(BigDecimal.ONE);
    }


    /**
     * 按日期分组查询支付订单数量
     *
     * @param beginDate 开始时间
     * @param endDate   结束时间
     * @param status    订单状态
     * @return 按日期分组的数据
     */
    private List<ChartDataItem> getPaymentDataByDay(Date beginDate, Date endDate, Integer status) {
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("DATE_FORMAT(pay_time, '%Y-%m-%d') AS day", "COUNT(1) AS num");
        queryWrapper.eq("status", status);
        queryWrapper.ge("pay_time", DateUtils.getDayStartTime(beginDate));
        queryWrapper.le("pay_time", DateUtils.getDayEndTime(endDate));
        queryWrapper.groupBy("day");
        queryWrapper.orderByAsc("day");

        // 执行查询
        List<Map<String, Object>> results = this.baseMapper.selectMaps(queryWrapper);

        // 日期解析器
        SimpleDateFormat outputFormat = new SimpleDateFormat("M月d日");

        // 映射到 ChartDataItem
        List<ChartDataItem> dataList = results.stream().map(result -> {
            ChartDataItem item = new ChartDataItem();
            // 获取日期字符串
            String dayStr = result.get("day").toString();
            // 解析为Date对象，然后格式化为所需的输出格式
            Date date = DateUtils.parse(dayStr, DateUtils.FMT_YMD);
            item.setX(outputFormat.format(date));
            item.setY(((Number) result.get("num")).intValue()); // 修改为Integer类型
            return item;
        }).collect(Collectors.toList());

        // 填充没有数据的日期
        List<ChartDataItem> filledDataList = fillEmptyDates(dataList, beginDate, endDate);

        return filledDataList;
    }

    /**
     * 填充没有数据的日期
     *
     * @param dataList  原始数据列表
     * @param beginDate 开始日期
     * @param endDate   结束日期
     * @return 填充后的数据列表
     */
    private List<ChartDataItem> fillEmptyDates(List<ChartDataItem> dataList, Date beginDate, Date endDate) {
        // 创建日期到数据的映射
        Map<String, ChartDataItem> dateDataMap = dataList.stream()
                .collect(Collectors.toMap(
                        item -> item.getX(),
                        item -> item
                ));

        // 创建结果列表
        List<ChartDataItem> result = new ArrayList<>();

        // 当前日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(beginDate);
        Calendar endCalendar = Calendar.getInstance();
        endCalendar.setTime(endDate);
        endCalendar.add(Calendar.DAY_OF_MONTH, 1); // 包含结束日期

        // 创建日期格式化对象
        SimpleDateFormat outputFormat = new SimpleDateFormat("M月d日");

        // 遍历日期范围
        while (calendar.getTime().before(endCalendar.getTime())) {
            // 直接使用SimpleDateFormat格式化Date对象
            String dateStr = outputFormat.format(calendar.getTime());

            // 如果日期存在数据，使用已有数据；否则创建新数据（金额为0）
            if (dateDataMap.containsKey(dateStr)) {
                result.add(dateDataMap.get(dateStr));
            } else {
                ChartDataItem item = new ChartDataItem();
                item.setX(dateStr);
                item.setY(0);
                result.add(item);
            }

            // 日期加1
            calendar.add(Calendar.DAY_OF_MONTH, 1);
        }

        return result;
    }

    /**
     * 计算转换率
     *
     * @param numerator   分子（已支付订单数）
     * @param denominator 分母（总订单数）
     * @return 转换率，如果分母为0，则返回0
     */
    private BigDecimal calculateConversionRate(long numerator, long denominator) {
        if (denominator == 0) {
            return BigDecimal.ZERO;
        }

        BigDecimal numeratorDecimal = new BigDecimal(numerator);
        BigDecimal denominatorDecimal = new BigDecimal(denominator);

        // 计算百分比，保留2位小数
        return numeratorDecimal.divide(denominatorDecimal, 4, BigDecimal.ROUND_HALF_UP)
                .multiply(new BigDecimal("100"))
                .setScale(2, BigDecimal.ROUND_HALF_UP);
    }


    /**
     * 填充没有数据的日期（金额版本）
     *
     * @param dataList  原始数据列表
     * @param beginDate 开始日期
     * @param endDate   结束日期
     * @return 填充后的数据列表
     */
    private List<ChartDataItem> fillEmptyDatesWithAmount(List<ChartDataItem> dataList, Date beginDate, Date endDate) {
        // 创建日期到数据的映射
        Map<String, ChartDataItem> dateDataMap = dataList.stream()
                .collect(Collectors.toMap(
                        item -> item.getX(),
                        item -> item
                ));

        // 创建结果列表
        List<ChartDataItem> result = new ArrayList<>();

        // 当前日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(beginDate);
        Calendar endCalendar = Calendar.getInstance();
        endCalendar.setTime(endDate);
        endCalendar.add(Calendar.DAY_OF_MONTH, 1); // 包含结束日期

        // 日期解析器
        SimpleDateFormat outputFormat = new SimpleDateFormat("M月d日");

        // 遍历日期范围
        while (calendar.getTime().before(endCalendar.getTime())) {
            // 直接使用SimpleDateFormat格式化Date对象
            String dateStr = outputFormat.format(calendar.getTime());
            // 如果日期存在数据，使用已有数据；否则创建新数据（金额为0）
            if (dateDataMap.containsKey(dateStr)) {
                result.add(dateDataMap.get(dateStr));
            } else {
                ChartDataItem item = new ChartDataItem();
                item.setX(dateStr);
                item.setY(0);
                result.add(item);
            }

            // 日期加1
            calendar.add(Calendar.DAY_OF_MONTH, 1);
        }

        return result;
    }


    /**
     * 按小时分组查询销售额
     *
     * @param beginDate 开始时间
     * @param endDate   结束时间
     * @param status    订单状态
     * @return 按小时分组的销售数据
     */
    private List<ChartDataItem> getSalesDataByHour(Date beginDate, Date endDate, Integer status) {
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("DATE_FORMAT(pay_time, '%H:00') AS hour", "SUM(amount) AS amount");
        queryWrapper.eq("status", status);
        queryWrapper.ge("pay_time", beginDate);
        queryWrapper.le("pay_time", endDate);
        queryWrapper.groupBy("hour");
        queryWrapper.orderByAsc("hour");

        // 执行查询
        List<Map<String, Object>> results = this.baseMapper.selectMaps(queryWrapper);

        // 映射到 ChartDataItem
        List<ChartDataItem> dataList = results.stream().map(result -> {
            ChartDataItem item = new ChartDataItem();
            item.setX(result.get("hour").toString());
            item.setY(((Number) result.get("amount")).intValue());
            return item;
        }).collect(Collectors.toList());

        // 填充24小时
        List<ChartDataItem> filledDataList = new ArrayList<>();
        Map<String, ChartDataItem> hourDataMap = dataList.stream()
                .collect(Collectors.toMap(ChartDataItem::getX, item -> item));

        for (int i = 0; i < 24; i++) {
            String hour = String.format("%02d:00", i);
            if (hourDataMap.containsKey(hour)) {
                filledDataList.add(hourDataMap.get(hour));
            } else {
                ChartDataItem item = new ChartDataItem();
                item.setX(hour);
                item.setY(0);
                filledDataList.add(item);
            }
        }

        return filledDataList;
    }

    /**
     * 按月份分组查询销售额
     *
     * @param beginDate 开始时间
     * @param endDate   结束时间
     * @param status    订单状态
     * @return 按月份分组的销售数据
     */
    private List<ChartDataItem> getSalesDataByMonth(Date beginDate, Date endDate, Integer status) {
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("DATE_FORMAT(pay_time, '%Y-%m') AS month", "SUM(amount) AS amount");
        queryWrapper.eq("status", status);
        queryWrapper.ge("pay_time", beginDate);
        queryWrapper.le("pay_time", endDate);
        queryWrapper.groupBy("month");
        queryWrapper.orderByAsc("month");

        // 执行查询
        List<Map<String, Object>> results = this.baseMapper.selectMaps(queryWrapper);

        // 映射到 ChartDataItem，并转换为所需的月份格式
        List<ChartDataItem> dataList = results.stream().map(result -> {
            ChartDataItem item = new ChartDataItem();
            // 获取原始月份字符串，格式为 YYYY-MM
            String monthStr = result.get("month").toString();
            // 解析月份
            String[] parts = monthStr.split("-");
            if (parts.length == 2) {
                // 去掉前导零，如 "05" -> "5"
                int month = Integer.parseInt(parts[1]);
                // 设置为 "M月" 格式
                item.setX(String.format("%d月", month));
                item.setY(((Number) result.get("amount")).intValue());
            } else {
                // 异常情况处理
                item.setX(monthStr);
                item.setY(((Number) result.get("amount")).intValue());
            }
            return item;
        }).collect(Collectors.toList());

        // 填充月份
        Calendar startCal = Calendar.getInstance();
        startCal.setTime(beginDate);
        Calendar endCal = Calendar.getInstance();
        endCal.setTime(endDate);

        List<ChartDataItem> filledDataList = new ArrayList<>();
        Map<String, ChartDataItem> monthDataMap = dataList.stream()
                .collect(Collectors.toMap(ChartDataItem::getX, item -> item));

        while (startCal.before(endCal) || startCal.equals(endCal)) {
            // 月份从0开始
            int month = startCal.get(Calendar.MONTH) + 1;
            String monthStr = String.format("%d月", month);

            if (monthDataMap.containsKey(monthStr)) {
                filledDataList.add(monthDataMap.get(monthStr));
            } else {
                ChartDataItem item = new ChartDataItem();
                item.setX(monthStr);
                item.setY(0);
                filledDataList.add(item);
            }

            startCal.add(Calendar.MONTH, 1);
        }

        return filledDataList;
    }

    /**
     * 按日期分组查询销售额
     *
     * @param beginDate 开始时间
     * @param endDate   结束时间
     * @param status    订单状态
     * @return 按日期分组的销售数据
     */
    private List<ChartDataItem> getSalesDataByDay(Date beginDate, Date endDate, Integer status) {
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("DATE_FORMAT(pay_time, '%Y-%m-%d') AS day", "SUM(amount) AS amount");
        queryWrapper.eq("status", status);
        queryWrapper.ge("pay_time", DateUtils.getDayStartTime(beginDate));
        queryWrapper.le("pay_time", DateUtils.getDayEndTime(endDate));
        queryWrapper.groupBy("day");
        queryWrapper.orderByAsc("day");

        // 执行查询
        List<Map<String, Object>> results = this.baseMapper.selectMaps(queryWrapper);

        // 日期解析器
        SimpleDateFormat outputFormat = new SimpleDateFormat("M月d日");

        // 映射到 ChartDataItem
        List<ChartDataItem> dataList = results.stream().map(result -> {
            ChartDataItem item = new ChartDataItem();
            // 获取日期字符串
            String dayStr = result.get("day").toString();
            // 解析为Date对象，然后格式化为所需的输出格式
            Date date = DateUtils.parse(dayStr, DateUtils.FMT_YMD);

            item.setX(outputFormat.format(date));
            item.setY(((Number) result.get("amount")).intValue());
            return item;
        }).collect(Collectors.toList());

        // 填充没有数据的日期
        List<ChartDataItem> filledDataList = fillEmptyDatesWithAmount(dataList, beginDate, endDate);

        return filledDataList;
    }

}
